package com.xayy.health.mgt.service.impl;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.xayy.health.core.antlr4.visitor.HealthEvaluateVisitor;
import com.xayy.health.core.enums.ScoreRuleEnum;
import com.xayy.health.mgt.mapper.HealthAssessAutoRunResultMapper;
import com.xayy.health.mgt.mapper.SatelliteNodeMapper;
import com.xayy.health.mgt.model.*;
import com.xayy.health.mgt.model.dto.TaskInfoDto;
import com.xayy.health.mgt.model.vo.*;
import com.xayy.health.mgt.service.*;
import com.xayy.health.mgt.service.strategy.AlgorithmStrategy;
import com.xayy.health.mgt.service.strategy.HealthAlgorithmEnum;

import cn.kawins.base.result.CheckResult;
import cn.kawins.base.utils.BeanUtil;
import cn.kawins.mybatis.base.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import tk.mybatis.mapper.entity.Example;

/**
 * 健康态势评估自动任务
 * 
 * @author shichenlei
 */
@Service
@Slf4j
public class HealthAutoRunServiceImpl extends BaseServiceImpl<HealthAssessTaskResult> implements HealthAutoRunService {
    @Autowired
    private SatelliteNodeService satelliteNodeService;

    @Autowired
    private FaultInfoService faultInfoService;

    @Autowired
    private FractionIntervalScoreService fractionIntervalScoreService;

    @Autowired
    private HealthAssessResultServiceImpl healthAssessResultServiceImpl;

    @Autowired
    private HealthAssessAutoRunResultMapper healthAssessAutoRunResultMapper;
    @Autowired
    private TaskChildInfoService taskChildInfoService;

    @Autowired
    private SatelliteNodeMapper satelliteNodeMapper;
    @Autowired
    private SatelliteCodeService satelliteCodeService;

    /**
     * 健康态势评估自动任务
     */
    @Override
    public void healthAutoRunTask(CalculateVo calculateVo) {
        calculate(calculateVo);
    }

    /**
     * 计算根节点分数
     *
     * @param calculateVo
     *            入参信息
     * @return 结果信息
     */

    private void calculate(CalculateVo calculateVo) {
        if (BeanUtil.isEmpty(calculateVo.getFractionTime())) {
            log.error("未设置卫星节点配置评估时间...calculateVo={}", calculateVo);
            return;
        }
        AlgorithmStrategy<HealthAssessParam> healthStrategy =
            HealthAlgorithmEnum.mathAlgorithm(calculateVo.getAlgorithmType());
        if (Objects.isNull(healthStrategy)) {
            log.error("未匹配到相关算法...calculateVo={}", calculateVo);
            return;
        }
        /*查询卫星只是拓扑结构*/
        SatelliteNode satellite =
            SatelliteNode.builder().id(calculateVo.getSatelliteId()).xing(calculateVo.getSatelliteName()).build();
        // 卫星
        List<SatelliteNodeTreeVo> satelliteNodeList = satelliteNodeService.getTreeList(satellite);
        // Map<Long, List<SatelliteNodeTreeVo>> satMap =
        // satelliteNodeList.stream().collect(Collectors.groupingBy(SatelliteNodeTreeVo::getId));
        List<SatelliteNodeTreeVo> treeVoList = cn.kawins.base.utils.TreeUtil.toTree(0L, satelliteNodeList);
        SatelliteNodeTreeVo defRoot = treeVoList.get(0);
        if (BeanUtil.isEmpty(defRoot)) {
            log.error("没有获取到卫星结构信息...calculateVo={}", calculateVo);
            return;
        }
        // List<HealthAssessResult> assessResults =
        // select(HealthAssessResult.builder().satelliteMid(calculateVo.getSatelliteId()).build());
        // 最新的节点mid集合
        // Set<Long> currentMidList =
        // satelliteNodeList.stream().map(SatelliteNodeTreeVo::getId).collect(Collectors.toSet());
        // 库里的已经评分过的mid集合
        // Set<Long> dbMidList = assessResults.stream().map(HealthAssessResult::getNodeMid).collect(Collectors.toSet());
        // 库里有评分，但是获取的最新节点里没有的，证明装备画像那边已经删除节点，需要从评分库删除，防止脏数据
        // List<Long> delIds = assessResults.stream().map(HealthAssessResult::getNodeMid)
        // .filter(aLong -> !currentMidList.contains(aLong)).collect(Collectors.toList());
        // deleteByIds(delIds);
        // 从数据库删除的评分数据也需要从刚才查询出来的list中删除
        // assessResults.removeIf(x -> delIds.contains(x.getId()));

        // 库里没有评分的节点list，此部分节点需要在库里插入评分信息
        // List<SatelliteNodeTreeVo> dataList =
        // satelliteNodeList.stream().filter(x -> !dbMidList.contains(x.getId())).collect(Collectors.toList());

        List<CalculateNodeVo> calculateNodeVoList = satelliteNodeList.stream().map(x -> {
            CalculateNodeVo calculateNodeVo = new CalculateNodeVo();
            calculateNodeVo.setSatId(calculateVo.getSatelliteId());
            calculateNodeVo.setSatName(calculateVo.getSatelliteName());
            calculateNodeVo.setParentId(x.getPid());
            calculateNodeVo.setComponentId(x.getId());
            calculateNodeVo.setTaskId(calculateVo.getTaskId());
            calculateNodeVo.setComponentName(x.getName());
            calculateNodeVo.setFractionTime(calculateVo.getFractionTime());
            return calculateNodeVo;
        }).collect(Collectors.toList());

        // 找到需要规则打分的节点，新增的全部规则打分加上库里配了规则打分的节点
        // List<HealthAssessResult> collect =
        // assessResults.stream().filter(x -> x.getScoringRule() == 2).collect(Collectors.toList());
        // List<CalculateNodeVo> ruleList = collect.stream().map(x -> {
        // CalculateNodeVo calculateNodeVo = new CalculateNodeVo();
        // calculateNodeVo.setSatId(calculateVo.getSatelliteId());
        // calculateNodeVo.setSatName(calculateVo.getSatelliteName());
        // calculateNodeVo.setComponentId(x.getNodeMid());
        // calculateNodeVo.setComponentName(x.getNodeName());
        // List<SatelliteNodeTreeVo> satelliteNodeTreeVos = satMap.get(x.getNodeMid());
        // if (CollUtil.isNotEmpty(satelliteNodeTreeVos)) {
        // calculateNodeVo.setComponentName(satelliteNodeTreeVos.get(0).getName());
        // }
        // calculateNodeVo.setFractionTime(calculateVo.getFractionTime());
        // return calculateNodeVo;
        // }).collect(Collectors.toList());
        // ruleList.addAll(calculateNodeVoList);
        // 规则打分
        // ThreadPoolExecutor threadPoolExecutor = ThreadUtil.newExecutor(8, 10);
        // 对未打分的节点走规则打分
        SatelliteCode satelliteCode = satelliteCodeService
            .selectOne(SatelliteCode.builder().satelliteId(String.valueOf(calculateVo.getSatelliteId())).build());
        if (BeanUtil.isEmpty(satelliteCode)) {
            log.error("卫星code不存在...calculateVo={}", calculateVo);
            return;
        }
        HealthEvaluateVisitor visitor =
            new HealthEvaluateVisitor(satelliteCode.getSatelliteCode(), calculateVo.getFractionTime());
        calculateNodeVoList.forEach((x) -> regularScoring(x, visitor));
    }

    /**
     * 规则打分
     *
     * @param calculateNodeVo
     *            入参
     */
    private void regularScoring(CalculateNodeVo calculateNodeVo, HealthEvaluateVisitor visitor) {

        String satisfaction = "无";
        // 计算故障分值
        List<FaultInfo> faultInfos =
            faultInfoService.selectByArgs(calculateNodeVo.getSatId(), calculateNodeVo.getComponentId(),
                calculateNodeVo.getFractionTime(), calculateNodeVo.getFractionStartTime()).getData();
        Integer faultScore = healthAssessResultServiceImpl.autoCalculateFaultScore(faultInfos);
        if (faultScore == null) {
            faultScore = 100;
        }
        // 获取打分日志
        String faultMsg = healthAssessResultServiceImpl.faultRule(faultInfos, faultScore,
            calculateNodeVo.getComponentName(), calculateNodeVo.getFractionTime());

        // 性能评分
        Integer performanceScore = healthAssessResultServiceImpl
            .autoCalculatePerformanceScore(calculateNodeVo.getSatId(),calculateNodeVo.getParentId(), calculateNodeVo.getComponentId(), visitor);
        // 获取性能打分日志
        if (performanceScore == null) {
            performanceScore = 100;
        }
        // 性能打分日志
        String natureMsg = healthAssessResultServiceImpl.calculateRule(calculateNodeVo, performanceScore);
        CheckResult<FractionIntervalScoreVo> fractionResult =
            fractionIntervalScoreService.selectByType(ScoreRuleEnum.HEALTH.getCode());

        HealthAssessResult healthAssessResult = healthAssessResultServiceImpl
            .selectOne(HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .parentId(calculateNodeVo.getParentId()).nodeMid(calculateNodeVo.getComponentId()).build());
        if (Objects.nonNull(healthAssessResult)) {
            int multipleFraction = healthAssessResultServiceImpl.getMultipleFraction(faultScore, performanceScore,
                healthAssessResult.getFaultWeight() / 100D);
            if (fractionResult.isSuccess()) {
                satisfaction =
                    ScoreRuleEnum.matchLevelStr(fractionResult.getData().getIntervalList(), multipleFraction);
            }
            HealthAssessTaskResult healthAssessTaskResult = new HealthAssessTaskResult();
            healthAssessTaskResult.setSatelliteMid(healthAssessResult.getSatelliteMid());
            healthAssessTaskResult.setSatelliteName(healthAssessResult.getSatelliteName());
            healthAssessTaskResult.setParentId(healthAssessResult.getParentId());
            healthAssessTaskResult.setNodeMid(healthAssessResult.getNodeMid());
            healthAssessTaskResult.setNodeName(calculateNodeVo.getComponentName());
            healthAssessTaskResult.setIsComponent(healthAssessResult.getIsComponent());
            healthAssessTaskResult.setFaultFraction(faultScore);
            healthAssessTaskResult.setNatureFraction(performanceScore);
            healthAssessTaskResult.setMultipleFraction(multipleFraction);
            healthAssessTaskResult.setSatisfaction(satisfaction);
            healthAssessTaskResult.setFinishFraction(healthAssessResult.getFinishFraction());
            healthAssessTaskResult.setFractionTime(calculateNodeVo.getFractionTime());
            healthAssessTaskResult.setAutoScore(true);
            healthAssessTaskResult.setFaultWeight(healthAssessResult.getFaultWeight());
            healthAssessTaskResult.setScoringRule(2);
            healthAssessTaskResult.setFaultFactionIntroduction(faultMsg);
            healthAssessTaskResult.setNatureFactionIntroduction(natureMsg);
            healthAssessTaskResult.setEvaluatingWeight(healthAssessResult.getEvaluatingWeight());
            healthAssessTaskResult.setTaskId(calculateNodeVo.getTaskId());
            insert(healthAssessTaskResult);
        } else {
            int multipleFraction =
                healthAssessResultServiceImpl.getMultipleFraction(faultScore, performanceScore, 0.8D);
            if (fractionResult.isSuccess()) {
                satisfaction =
                    ScoreRuleEnum.matchLevelStr(fractionResult.getData().getIntervalList(), multipleFraction);
            }
            HealthAssessTaskResult result = HealthAssessTaskResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .multipleFraction(multipleFraction).faultFraction(faultScore).natureFraction(performanceScore)
                .faultWeight(80D).fractionTime(calculateNodeVo.getFractionTime()).isComponent(true).finishFraction(true)
                .autoScore(true).parentId(calculateNodeVo.getParentId()).nodeMid(calculateNodeVo.getComponentId())
                .satisfaction(satisfaction).scoringRule(2).faultFactionIntroduction(faultMsg)
                .natureFactionIntroduction(natureMsg).evaluatingWeight(0D).taskId(calculateNodeVo.getTaskId())
                .nodeName(calculateNodeVo.getComponentName()).build();
            // 手动表中没有任何记录时向手动表中插入
            HealthAssessResult healthResult = HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .multipleFraction(multipleFraction).faultFraction(faultScore).natureFraction(performanceScore)
                .faultWeight(80D).fractionTime(new Date()).isComponent(true).finishFraction(true).autoScore(true)
                .parentId(calculateNodeVo.getParentId()).nodeMid(calculateNodeVo.getComponentId())
                .satisfaction(satisfaction).scoringRule(2).faultFactionIntroduction(faultMsg)
                .natureFactionIntroduction(natureMsg).evaluatingWeight(0D).build();
            insert(result);
            healthAssessResultServiceImpl.insertSelective(healthResult);
        }

    }

    /**
     * 查询一次自动运行的结果
     * 
     * @param taskInfoDto
     *            任务查询信息
     * @return 分页后的
     */
    @Override
    public PageInfo<HealthAssessTaskResult> getHealthRunTaskResult(TaskInfoDto taskInfoDto) {
        PageMethod.startPage(taskInfoDto.getPage(), taskInfoDto.getSize());
        Long taskId = taskInfoDto.getTaskId();
        Example example = new Example(HealthAssessTaskResult.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("taskId", taskId);
        List<HealthAssessTaskResult> resultList = selectByExample(example);
        return new PageInfo<>(resultList);
    }

    /**
     * 设置 calculateVo 运行信息
     * 
     * @param x
     *            运行任务
     * @param endTime
     *            结束时间
     * @param id
     *            子任务id
     * @return 运行信息
     */
    @Override
    public CalculateVo setHealthAutoRunTaskInfo(TaskInfo x, Date endTime, Long id) {
        SatelliteCode satelliteCode = satelliteNodeMapper.getSateInfo(x.getSatelliteCode());
        CalculateVo calculateVo = new CalculateVo();
        calculateVo.setAlgorithmType(Integer.parseInt(x.getParams()));
        calculateVo.setFractionTime(endTime);
        calculateVo.setSatelliteName(satelliteCode.getSatelliteName());
        calculateVo.setTaskId(id);
        calculateVo.setSatelliteId(Long.parseLong(satelliteCode.getSatelliteId()));
        return calculateVo;
    }

}
